using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.SharedSource.SqlServer.MDDE.Middleware;
using System.Xml;

namespace Microsoft.SharedSource.SqlServer.MDDE.ManagementStudio
{
    internal partial class UpgradeTemplateSelectConfigurations : UpgradeTemplateBase
    {
        XmlDocument templateTree;
        bool templateConfigurationsLocked = false;
        XmlDocument templateConfigurations;
        XmlElement rootElement;

        internal UpgradeTemplateSelectConfigurations(UpgradeTemplateWizardController controller)
            : base(controller)
        {
            InitializeComponent();
        }

        private void UpgradeTemplateSelectConfigurations_VisibleChanged(object sender, EventArgs e)
        {
            // Do nothing if the visibility is false.
            if (this.Visible == false)
                return;

            // Check if we have the form configuration in the wizard configuration.
            XmlNode xFormConfiguration =
                controller.WizardConfigurations.SelectSingleNode(
                "//Form[@Name=\"SelectConfigurations\"]");

            if (xFormConfiguration == null)
            {
                // Disable all the controls.
                DisableControls();

                // Initialize the tree control.
                trvTemplateComponents.Nodes.Add("Loading data...");

                // Start off the worker thread.
                workerGetTemplateTree.RunWorkerAsync();
            }

        }

        Dictionary<Control, bool> controlState = new Dictionary<Control, bool>();

        private void DisableControls()
        {
            controlState.Clear();

            foreach (Control ctrl in this.Controls)
            {
                controlState.Add(ctrl, ctrl.Enabled);
                ctrl.Enabled = false;
            }

            this.Cursor = Cursors.WaitCursor;
        }

        private void EnableControls()
        {
            foreach (KeyValuePair<Control, bool> kvp in controlState)
                kvp.Key.Enabled = kvp.Value;

            this.Cursor = Cursors.Default;
        }

        private void workerGetTemplateTree_DoWork(object sender, DoWorkEventArgs e)
        {
            // Get the template body from wizard configurations.
            XmlNode xBody = controller.WizardConfigurations.SelectSingleNode(
                "//Form[@Name=\"GetTemplateLocation\"]/UserInput[@Name=\"TemplateBody\"]");

            string templateBody = xBody.Attributes["Value"].Value;

            // Get the template tree from backend.
            try
            {
                templateTree = MDDEManager.GetPackageTree(templateBody);
            }
            catch { }

            // Fetch the template configurations information.
            XmlNode xConfig = controller.WizardConfigurations.SelectSingleNode(
                "//Form[@Name=\"ShowDifferences\"]/UserInput[@Name=\"TemplateConfigurations\"]");
            templateConfigurations = new XmlDocument();
            templateConfigurations.LoadXml(xConfig.Attributes["Value"].Value);

            this.rootElement = (XmlElement)templateConfigurations.DocumentElement;

        }

        private void workerGetTemplateTree_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            trvTemplateComponents.Nodes.Clear();

            if (templateTree == null)
            {
                MessageBox.Show(
                       "Some errors occured while fetching template components.",
                       "Operation Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            // Populate the template information.
            trvTemplateComponents.Nodes.Clear();
            lblComponentName.Text = string.Empty;
            rtbComponentURI.Text = string.Empty;
            dgProperties.Rows.Clear();

            TemplateComponentNode tn =
                new TemplateComponentNode(templateTree.DocumentElement);

            tn.PopulateSubtree();

            trvTemplateComponents.Nodes.Add(tn);

            // Enable controls.
            EnableControls();
        }

        private void trvTemplateComponents_AfterSelect(object sender, TreeViewEventArgs e)
        {
            // Lock the configuration document.
            templateConfigurationsLocked = true;

            // Change the label texts.
            lblComponentName.Text = e.Node.Name;
            rtbComponentURI.Text = e.Node.FullPath;
            dgProperties.Rows.Clear();

            // Disable the mappings checkbox if the selected 
            // node is not of the type "Component".
            if (((XmlNode)e.Node.Tag).Attributes["Type"].Value.Equals(
                "Component", StringComparison.InvariantCultureIgnoreCase))
            {
                chkConfigurableMappings.Enabled = true;
                chkCollections.Enabled = true;
            }
            else
            {
                chkConfigurableMappings.Enabled = false;
                chkCollections.Enabled = false;
            }

            // Populate the grid and checkbox.
            XmlNode templateTreeNode = (XmlNode)e.Node.Tag;
            XmlNodeList propertyNodes =
                templateTreeNode.SelectNodes("./Property");

            // See if we have entry for this 
            // node in templateConfigurations.
            XmlNode configurationNode = templateConfigurations.
                SelectSingleNode(
                "//ConfigurableComponent[@ComponentUri=\"" +
                templateTreeNode.Attributes["Uri"].Value + "\"]");

            // Entry not found.
            if (configurationNode == null)
            {
                // Populate the grid with unchecked first column.
                foreach (XmlNode childNode in propertyNodes)
                    dgProperties.Rows.Add(null,
                        childNode.Attributes["Name"].Value);

                // Clear off the mappings checkbox. 
                chkConfigurableMappings.Checked = false;

                // Clear off the collections checkbox. 
                chkCollections.Checked = false;
            }
            // Entry found!
            else
            {
                XmlNode configurableProperty;
                // Populate the grid taking into account 
                // the earlier property values.
                foreach (XmlNode childNode in propertyNodes)
                {
                    // Check if we have this configurable 
                    // property already marked.
                    configurableProperty =
                        configurationNode.SelectSingleNode(
                        "./ConfigurableProperty[@Name=\"" +
                        childNode.Attributes["Name"].Value + "\"]");

                    if (configurableProperty == null)
                        dgProperties.Rows.Add(null,
                            childNode.Attributes["Name"].Value);
                    else
                        dgProperties.Rows.Add(true,
                            childNode.Attributes["Name"].Value);
                }

                // Populate the mappings checkbox with earlier 
                // mappings information.
                if (configurationNode.Attributes["ContainsMappings"].
                    Value == "True")
                    chkConfigurableMappings.Checked = true;
                else
                    chkConfigurableMappings.Checked = false;

                // Populate the collections checkbox with earlier 
                // collections information.
                if (configurationNode.Attributes["ContainsCollections"].
                    Value == "True")
                    chkCollections.Checked = true;
                else
                    chkCollections.Checked = false;
            }

            // Release the lock.
            templateConfigurationsLocked = false;
        }

        private void chkConfigurableMappings_CheckedChanged(object sender, EventArgs e)
        {
            // Do nothing if the configuration document is locked.
            if (templateConfigurationsLocked)
                return;

            // Lock the configurations document.
            templateConfigurationsLocked = true;

            // Get the configurations node for the selected component.
            XmlNode configurableComponent = GetSelectedComponent();

            // Update the mappings information.
            configurableComponent.Attributes["ContainsMappings"].
                Value =
                chkConfigurableMappings.Checked ? "True" : "False";

            // Check and remove empty component nodes.
            RemoveEmptyConfigurableComponent(configurableComponent);

            // Release the document lock.
            templateConfigurationsLocked = false;
        }

        private void chkCollections_CheckedChanged(object sender, EventArgs e)
        {
            // Do nothing if the configuration document is locked.
            if (templateConfigurationsLocked)
                return;

            // Lock the configurations document.
            templateConfigurationsLocked = true;

            // Get the configurations node for the selected component.
            XmlNode configurableComponent = GetSelectedComponent();

            // Update the collections information.
            configurableComponent.Attributes["ContainsCollections"].
                Value =
                chkCollections.Checked ? "True" : "False";

            // Check and remove empty component nodes.
            RemoveEmptyConfigurableComponent(configurableComponent);

            // Release the document lock.
            templateConfigurationsLocked = false;
        }

        private void dgProperties_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            // Do nothing if the configuration document is locked.
            if (templateConfigurationsLocked)
                return;

            if (e.RowIndex < 0 || e.RowIndex > dgProperties.Rows.Count - 1)
                return;

            // Lock the configurations document.
            templateConfigurationsLocked = true;

            // Get the configurations node for the selected component.
            XmlNode configurableComponent = GetSelectedComponent();

            // Add/Remove configurable property.
            string propertyName =
                dgProperties.Rows[e.RowIndex].
                Cells["propertyName"].Value.ToString();
            bool isConfigurable =
                (Boolean)dgProperties.Rows[e.RowIndex].
                Cells["isConfigurable"].Value;
            XmlNode configurableProperty;

            // Get the configurable property node.
            configurableProperty =
                configurableComponent.SelectSingleNode(
                "./ConfigurableProperty[@Name=\"" +
                propertyName + "\"]");

            // Add the configuration if the change 
            // is for inclusion of the property.
            if ((configurableProperty == null) && isConfigurable)
                UIHelper.AppendChildElement(
                    configurableComponent,
                    "ConfigurableProperty",
                    new string[] { 
                        "Name",propertyName
                        });

            // Remove the configuration if the change 
            // is for exclusion of the property.
            if ((configurableProperty != null) && !isConfigurable)
                configurableProperty.ParentNode.RemoveChild(
                    configurableProperty);

            // Check and remove empty component nodes.
            RemoveEmptyConfigurableComponent(configurableComponent);

            // Release the document lock.
            templateConfigurationsLocked = false;
        }

        protected override void btnNext_Click(object sender, EventArgs e)
        {
            // Locate any earlier entry for this form.
            XmlNode formSelectConfigurations =
                controller.WizardConfigurations.SelectSingleNode(
                "//Form[@Name=\"SelectConfigurations\"]");

            // Delete the earlier node if found.
            if (formSelectConfigurations != null)
                formSelectConfigurations.ParentNode.RemoveChild(formSelectConfigurations);

            // Create the form configuration node in the wizard configuration.
            XmlNode formNode =
                UIHelper.AppendChildElement(controller.WizardConfigurations.FirstChild, "Form",
                new string[] { "Name", "SelectConfigurations" });

            // Add the udpated template configurations to wizard configurations.
            UIHelper.AppendChildElement(formNode, "UserInput",
                new string[] { "Name","TemplateConfigurations",
                "Value", templateConfigurations.InnerXml});

            base.btnNext_Click(sender, e);
        }

        protected override void btnBack_Click(object sender, EventArgs e)
        {
            // Clear off all the controls.
            trvTemplateComponents.Nodes.Clear();
            lblComponentName.Text = string.Empty;
            rtbComponentURI.Text = string.Empty;
            dgProperties.Rows.Clear();
            chkCollections.Checked = false;
            chkConfigurableMappings.Checked = false;

            // Nullify the component information.
            templateTree = null;
            templateConfigurations = null;
            rootElement = null;
            bool templateConfigurationsLocked = false;

            // Locate any earlier entry for this form.
            XmlNode formSelectConfigurations =
                controller.WizardConfigurations.SelectSingleNode(
                "//Form[@Name=\"SelectConfigurations\"]");

            // Delete the earlier node if found.
            if (formSelectConfigurations != null)
                formSelectConfigurations.ParentNode.RemoveChild(formSelectConfigurations);

            base.btnBack_Click(sender, e);
        }
        
        private static void RemoveEmptyConfigurableComponent(XmlNode configurableComponent)
        {
            // If there are no configurable properties for this 
            // component, neither does it contain mappings,
            // nor it contains configurable column collections, remove it.
            if (!configurableComponent.HasChildNodes &&
                configurableComponent.Attributes["ContainsMappings"].
                Value == "False" &&
                configurableComponent.Attributes["ContainsCollections"].
                Value == "False")
                configurableComponent.ParentNode.RemoveChild(
                    configurableComponent);
        }

        private XmlNode GetSelectedComponent()
        {
            // Get the component node.
            XmlNode componentNode =
                (XmlNode)trvTemplateComponents.SelectedNode.Tag;

            // Pick out the component Uri.
            string componentUri =
                componentNode.Attributes["Uri"].Value;

            // See if we already have this component enlisted.
            XmlNode configurableComponent = rootElement.
                SelectSingleNode("//ConfigurableComponent[@ComponentUri=\"" +
                componentUri + "\"]");

            // Create a new node for this component 
            // if it does not exist already.
            if (configurableComponent == null)
                configurableComponent =
                    UIHelper.AppendChildElement(
                    rootElement,
                    "ConfigurableComponent",
                    new string[] {
                        "ComponentName", 
                        componentNode.Attributes["Name"].Value,
                        "ComponentClassId", 
                        componentNode.Attributes["ClassId"].Value,
                        "ComponentUri", 
                        componentNode.Attributes["Uri"].Value,
                        "ComponentType", 
                        componentNode.Attributes["Type"].Value,
                        "RowsetType", 
                        componentNode.Attributes["RowsetDescriptorType"].Value,
                        "ContainsMappings", 
                        "False",
                        "ContainsCollections", 
                        "False"
                    });

            return configurableComponent;
        }
    }
}